///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2009. Dimarik
//
///////////////////////////////////////////////////////////////////////////////

package
{

import flash.display.DisplayObject;
import flash.display.FrameLabel;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Stage;
import flash.errors.IllegalOperationError;
import flash.errors.InvalidSWFError;
import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.system.ApplicationDomain;
import flash.utils.getClassName;

/**
 *  @author				Dimarik
 *  @version			1.0
 *  @langversion		3.0
 *  @playerversion		9.0
 * 
 */

public class ApplicationFactory extends MovieClip {

	//-------------------------------------------------------------------------
	//
	//   Constructor
	//
	//-------------------------------------------------------------------------

	/**
	 * Constructor 
	 * @param 			documentClassName
	 */
	public function ApplicationFactory(documentClassName:String = null) {
		super();
		super.stop();

		this._documentClassName = documentClassName;
		this._stage = super.stage;

		super.addEventListener(Event.ADDED_TO_STAGE, 				this.handler_addedToStage,	false, int.MAX_VALUE);

		super.loaderInfo.addEventListener(Event.INIT,				this.handler_init,			false, int.MAX_VALUE);
		super.loaderInfo.addEventListener(Event.COMPLETE,			this.handler_complete,		false, int.MAX_VALUE);
		super.loaderInfo.addEventListener(ProgressEvent.PROGRESS,	this.handler_progress,		false, int.MAX_VALUE);
		super.loaderInfo.addEventListener(IOErrorEvent.IO_ERROR,	this.handler_error,			false, int.MAX_VALUE);
	}

	//-------------------------------------------------------------------------
	//
	//   Properties
	//
	//-------------------------------------------------------------------------

	/**
	 * @private
	 */
	private var _stage:			Stage;

	public function get stageOwner():Boolean {
		return this._stage != null;
	}

	//-------------------------------------------------------------------------
	//
	//   Private variables
	//
	//-------------------------------------------------------------------------

	/**
	 * @private
	 */
	private var _documentClassName:		String;

	/**
	 * @private
	 */
	private var _document:				DisplayObject;

	//-------------------------------------------------------------------------
	//
	//   Private methods
	//
	//-------------------------------------------------------------------------

	/**
	 * @private
	 */
	private function handler_addedToStage(event:Event):void {
		(event.target as IEventDispatcher).removeEventListener(event.type, arguments.callee);
		this._stage = super.stage;

		if (this._document)
			this.finalize();

		this.onComplete();
	}

	/**
	 * @private
	 */	
	private function finalize():void {
		this._stage.addChild(this._document);
		this._document = null;

		if (super.parent is Loader)
			new Sprite().addChild(this);

		super.parent.removeChild(this);
	}

	//-------------------------------------------------------------------------
	//
	//   Protected methods
	//
	//-------------------------------------------------------------------------

	protected function onInitialize():void {
		
	}

	protected function onProgress():void {
		
	}

	protected function onComplete():void {
		
	}

	protected function onError():void {
		
	}

	//-------------------------------------------------------------------------
	//
	//   Events handlers
	//
	//-------------------------------------------------------------------------

	/**
	 * @private
	 */	
	private function handler_init(event:Event):void {
		this.onInitialize();
	}

	/**
	 * @private
	 */	
	private function handler_progress(event:Event):void {
		this.onProgress();
	}

	/**
	 * @private
	 */	
	private function handler_error(event:Event):void {
		this.onError();
	}

	/**
	 * @private
	 */	
	private function handler_complete(event:Event):void {
		super.loaderInfo.removeEventListener(Event.INIT,				this.handler_init);
		super.loaderInfo.removeEventListener(Event.COMPLETE,			this.handler_complete);
		super.loaderInfo.removeEventListener(ProgressEvent.PROGRESS,	this.handler_progress);
		super.loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,		this.handler_error);

		super.nextFrame();

		//var appDomain:ApplicationDomain = super.loaderInfo.applicationDomain;
		var label:FrameLabel = super.currentLabels.pop() as FrameLabel;

		var documentClassName:	String; 

		if (this._documentClassName) {
			documentClassName = this._documentClassName;
		} else {
			documentClassName = label.name;
		}

		if (!documentClassName) {
			trace(super.loaderInfo.url);
			throw new InvalidSWFError();
		}

		var documentClass:	Class = super.loaderInfo.applicationDomain.getDefinition(documentClassName) as Class;
		this._document = new documentClass();

		if (this._stage)
			this.finalize();

	}

}
}